﻿#include "CELLSelectServer.h"

CELLSelectServer::CELLSelectServer()
{

}

CELLSelectServer::~CELLSelectServer()
{
	Close();
}

bool CELLSelectServer::DoNetEvents()
{
	// fd_set fdException;  // 异常集合
	// 计算可读集合
	if (_clients_change)
	{
		_clients_change = false;
		// 清理读集合
		FD_ZERO(&_fdRead);
		for (auto pClient : _clients)
		{
			SOCKET tmpsock = pClient.first;
			_maxSock = _maxSock < tmpsock ? tmpsock : _maxSock;
			FD_SET(tmpsock, &_fdRead);
		}
		memcpy(&_fdRead_bak, &_fdRead, sizeof(fd_set));
	}
	else
	{
		memcpy(&_fdRead, &_fdRead_bak, sizeof(fd_set));
	}

	// 计算可写集合
	bool bNeedWrite = false;
	FD_ZERO(&_fdWrite);
	// 检测所有客户端有数据发送，才加入可写检测
	for (auto pClient : _clients)
	{
		if (pClient.second->needWrite())
		{
			bNeedWrite = true;
			FD_SET(pClient.second->sockfd(), &_fdWrite);
		}
	}

	// memcpy(&fdException, &_fdRead_bak, sizeof(fd_set));

	// 1微秒没有数据就返回
	timeval ti{ 0, 1 };
	int ret = 0;
	if (bNeedWrite)
	{
		ret = select(_maxSock + 1, &_fdRead, &_fdWrite, nullptr, &ti);
	}
	else
	{
		ret = select(_maxSock + 1, &_fdRead, nullptr, nullptr, &ti);
	}

	if (ret < 0)
	{
		if (errno == EINTR)
		{
			return true;
		}

		CELLLog_pError("CELLServer %d select error exit", _id);
		return false;
	}
	else if (ret == 0)
	{
		// 没有可读或可写就跳过
		return true;
	}

	ReadData();
	WriteData();
	// 如果查询异常有，那么当作一次可写
	// WriteData(fdException);
	// CELLLog_Info("CELLServer OnRun select: fdR=%d, fdW=%d", fdRead.fd_count, fdWrite.fd_count);
	/*if (fdException.fd_count > 0)
	{
		CELLLog_Info("###fdExcepton=%d", fdException.fd_count);
	}*/
	return true;
}

// 处理DoNetEvents函数返回后的客户端发送的消息
void CELLSelectServer::ReadData()
{
	// 在循环中不改变迭代器指针，在循环中会删除元素，在这之间进行改变
	for (auto iter = _clients.begin(); iter != _clients.end(); )
	{
		// 客户端是否有数据发送过来
		if (FD_ISSET(iter->first, &_fdRead))
		{
			if (RecvData(iter->second) == SOCKET_ERROR)
			{
				OnClientLeave(iter->second);
				// 在这里进行迭代器指针的自增(后置++，先赋值再自增)
				auto iterOld = iter++;
				_clients.erase(iterOld);
				continue;
			}
		}
		// 在这里进行迭代器指针的自增
		++iter;
	}
}

// 处理select函数返回后的可写的客户端
void CELLSelectServer::WriteData()
{
	// 在循环中不改变迭代器指针，在循环中会删除元素，在这之间进行改变
	for (auto iter = _clients.begin(); iter != _clients.end(); )
	{
		// 客户端是否需要写和有数据发送过来
		if (iter->second->needWrite() && FD_ISSET(iter->first, &_fdWrite))
		{
			if (SOCKET_ERROR == iter->second->SendDataReal())
			{
				OnClientLeave(iter->second);
				// 在这里进行迭代器指针的自增(后置++，先赋值再自增)
				auto iterOld = iter++;
				_clients.erase(iterOld);
				continue;
			}
		}
		// 在这里进行迭代器指针的自增
		++iter;
	}
}
